package com.call.project.web.controller;

import com.call.project.entity.Meeting;
import com.call.project.entity.WebSocketEntity;
import com.call.project.jni.CInterface;
import com.call.project.jni.MsgCallBack;
import com.call.project.utils.ConfigUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by IntelliJ IDEA.
 * User: wk
 * Date: 2017-03-20 下午10:05
 */
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketController implements MsgCallBack {
    private Logger     logger = LoggerFactory.getLogger(WebSocketController.class);
    public static Gson gson   = null;

    static {
        gson = new GsonBuilder().serializeNulls().create();
        gson.serializeNulls();
    }

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int                                       onlineCount  = 0;
    public final static LinkedBlockingQueue<WebSocketEntity> QUEUE        = new LinkedBlockingQueue<>();
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    public final static CopyOnWriteArraySet<Session>         webSocketSet = new CopyOnWriteArraySet<Session>();

    private CInterface                                       cInterface;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        webSocketSet.add(session); //加入set中
        addOnlineCount(); //在线数加1
        logger.info("有新连接加入！当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this); //从set中删除
        subOnlineCount(); //在线数减1
        logger.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("来自客户端的消息:" + message);

    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("发生错误");
        error.printStackTrace();
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        onlineCount--;
    }

    /**
     * c端回掉消息
     *
     * @param msg
     */
    @Override
    public void sendMsg(char msg) {
        int number = msg;
        boolean isopen = false;
        int index = number / 16;
        if (number % 2 != 0) {
            isopen = true;
            number = number - 1;
        }
        int button = (number % 16) / 2;
        WebSocketEntity frameEntity = new WebSocketEntity();
        frameEntity.setIndex(index);
        frameEntity.setOpen(isopen);
        frameEntity.setButton(button);
        frameEntity.setCommand(1);
        QUEUE.add(frameEntity);
    }

    public void setCInteface(CInterface cInterface) {
        this.cInterface = cInterface;
    }

    private volatile MyThread myThread;

    @PostConstruct
    public void init() {
        myThread = new MyThread();
        myThread.start();
    }

    @PreDestroy
    public void destory() {
        myThread.setFlag(false);
    }

    private class MyThread extends Thread {
        private boolean flag = true;

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }

        public String getRealMsg(String msg) {
            StringBuilder stringBuilder = new StringBuilder();
            for (char c : msg.toCharArray()) {
                stringBuilder.append(c);
                if (c >= '0' && c <= '9') {
                    stringBuilder.append(" ");
                }
            }
            return stringBuilder.toString();
        }

        @Override
        public void run() {
            super.run();
            while (flag) {
                try {
                    WebSocketEntity webSocketEntity = QUEUE.take();
                    HashMap<Integer, Meeting> meetingHashMap = ConfigUtils.getMeeting();
                    Meeting meeting = meetingHashMap.get(webSocketEntity.getIndex());
                    if (meeting == null) {
                        logger.warn("index not have meeting {}", webSocketEntity.getIndex());
                        return;
                    }
                    for (Session session : webSocketSet) {
                        try {
                            RemoteEndpoint.Basic basic = session.getBasicRemote();
                            basic.sendText(gson.toJson(webSocketEntity));
                            logger.info("send msg {}", gson.toJson(webSocketEntity));
                        } catch (Exception e) {
                            logger.error("sendMsg error", e);
                        }
                    }
                    if (cInterface != null && ConfigUtils.BUTTON_MSG.get(webSocketEntity.getButton()) != null) {
                        String msg = meeting.getName() + ConfigUtils.BUTTON_MSG.get(webSocketEntity.getButton());
                        msg = getRealMsg(msg);
                        if (webSocketEntity.getOpen()) {
                            cInterface.speek(msg);
                            cInterface.speek(msg);
                        } else {
                            cInterface.speek(msg + "取消");
                            cInterface.speek(msg + "取消");
                        }
                    }
                } catch (Exception e) {
                    logger.error("MyThread", e);
                }
            }
        }
    }
}
